;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                         ;;
;; [This macro was written by Bob Young at Ernst & Whinney in Washington,  ;;
;;  D.C.  Any comments or questions would be appreciated.  You may make    ;;
;;  comments via the BRIEF EBB or contact me directly at (202) 862-6339. ] ;;
;;                                                                         ;;
;; MACRO COMPARE.M  (Version 2.0+ BRIEF ONLY)                              ;;
;; ==========================================                              ;;
;;                                                                         ;;
;; To compare two windows (representing DIFFERENT buffers) of text,        ;;
;; place the cursor at the points you wish to start comparing in EACH      ;;
;; window (normally top_of_buffer).                                        ;;
;;                                                                         ;;
;; Press <F-10> and type "compare".  The program will ask you to point     ;;
;; (with the arrow keys) to the second window.  If there is an appropriate ;;
;; window there, comparison will begin, otherwise an error message will    ;;
;; print.  You may abort the compare process by hitting <ESC> instead      ;;
;; of an arrow key.                                                        ;;
;;                                                                         ;;
;; If a discrepency is encountered the program stops, leaving the          ;;
;; cursors one character after the first difference encountered            ;;
;; in each window, and displays an error message showing an 11-character   ;;
;; fragment of each line with the disagreeing characters as the            ;;
;; middle-most characters in the two strings.                              ;;
;;                                                                         ;;
;; You may continue comparison by pressing <Alt-J>.  Once and end-of-file  ;;
;; is encountered the <Alt-J> is disabled, and you must type <F-10>        ;;
;; "compare" to re-start comparison.                                       ;;
;;                                                                         ;;
;; The <Alt-J> hot key may be replaced by one of your choosing by          ;;
;; editing the appropriate line, and recompiling this macro.               ;;
;;                                                                         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(macro compare
   (
      (extern center_line)
      (int input_char char_cntr eob_flag err_flag loop)
      (int wndw1 wndw2 buf1 buf2 line1 col1 line2 col2)
      (int orig_line1 orig_col1 orig_line2 orig_col2)
      (string string1 string2 err_string)
      (string hot_key)

      (= hot_key "<Alt-J>")                        ;<=== EDIT THIS LINE
                                                   ;     TO CHANGE HOTKEY

      (inq_position orig_line1 orig_col1)          ;save original position
                                                   ;in window 1 if no
                                                   ;mismatch is encountered

      (= buf1 (inq_buffer))                        ;get buffer_id #1

      (= wndw1 (inq_window))                       ;get window_id #1

      (while 1
         (
            (message "Point to window to compare ...")

            (while (! (inq_kbd_char)))             ;wait for input

            (= input_char (read_char))             ;read the character
                                                    
            (if (== 0 (% input_char 256))          ;check if it's extended
               (
                  (= input_char (/ input_char 256))   ;get scan code

                  (switch input_char                  ;set appropriate
                                                      ;direction value   
                     72                ;up arrow
                        (
                           (= wndw2 0)
                           (break)
                        )
                     77                ;right arrow
                        (
                           (= wndw2 1)
                           (break)
                        )
                     80                ;down arrow
                        (
                           (= wndw2 2)
                           (break)
                        )
                     75                ;left arrow
                        (
                           (= wndw2 3)
                           (break)
                        )
                     ;default
                        NULL
                  )
               )
            ;else
               (if (== 27 (% input_char 256))      ;check for <ESC>
                  (
                     (beep)
                     (message "Aborted...")
                     (return -1)
                  )
               )
            )
            (beep)                                 ;neither arrow key
                                                   ;nor <ESC> hit --
                                                   ;loop back for another
                                                   ;key
         )
      )

      (if (< (change_window wndw2) 0)              ;is change unsuccessful?
                                                   ;i.e., checks for valid
                                                   ;second window
         (
            (beep)                                 ;if not valid -- error
            (return -1)
         )
      )

      (inq_position orig_line2 orig_col2)          ;save original position
                                                   ;in window 2 if no
                                                   ;mismatch is encountered


      (= buf2 (inq_buffer))                        ;get buffer_id #2

      (= wndw2 (inq_window))                       ;get window_id #2

      (set_window wndw1)                           ;go back to original window

      (if (== buf1 buf2)                           ;check to see if we're
                                                   ;attempting to compare
                                                   ;same buffer -- pointless!!
         (
            (beep)                                 ;if so -- error
            (error "Comparing same file ...")
            (return -1)
         )
      )

      (message "Comparing windows ...")


      (assign_to_key hot_key "compare")            ;sets up hot key to
                                                   ;continuing comparing
                                                   ;after mismatch
      (while 1
         (
            (set_buffer buf1)                      ;compare off-screen
            (inq_position line1 col1)              ;get current position
            (= string1 (read))                     ;read string1 in first
            (beginning_of_line)                    ;reposition
            (= err_flag (move_rel 1 0))            ;go to next line
            (if (== err_flag 0) (= eob_flag 1))    ;if no next line set flag
   
            (set_buffer buf2)                      ;go to second buffer
            (inq_position line2 col2)              ;get current position
            (= string2 (read))                     ;read string2 in next
            (beginning_of_line)                    ;reposition
            (= err_flag (move_rel 1 0))            ;go to next line
            (if (&& (== err_flag 0) (== eob_flag 1))  ;if no next line
                                                      ;and buffer #1 ALSO
                                                      ;had no next line
                                                      ;(i.e., flag set)
                                                      ;we're at end of files
               (
                  (while (< loop 5)                ;signal OK with 5 beeps
                     (
                        (beep)
                        (= char_cntr 0)
                        (while (< char_cntr 50) (+= char_cntr 1)) ;time delay
                        (+= loop 1)
                     )
                  )
                  (set_window wndw2)               ;change to window #2
                  (attach_buffer buf2)             ;attach buffer #2 to it
                  (move_abs orig_line2 orig_col2)  ;go to position at start
                                                   ;of this compare
                  (refresh)                        ;refresh screen

                  (set_window wndw1)               ;change to window #1
                                                   ;and do same thing
                  (attach_buffer buf1)
                  (move_abs orig_line1 orig_col1)
                  (refresh)

                  (message "End of files reached ... no differences!")
                  (assign_to_key hot_key "nothing")     ;clear hot key

                  (return 0)                            ;NORMAL EXIT
               )
            )
   
            (if (&& (== err_flag 0) (!= eob_flag 1))    ;Buffer #2 ran out
                                                        ;before #1 did
               (
                  (beep)                                ;error return
                  (refresh)
                  (set_buffer buf1)
                  (refresh)
                  (error "Premature end-of-file reached!")
                  (assign_to_key hot_key "nothing")     ;clear hot key

                  (return -1)
               )
            )
   
            (if (!= string1 string2)               ;mismatch found
               (
                  (= char_cntr 1)

                  (while (== (substr string1 char_cntr 1) (substr string2 char_cntr 1))
                     (+= char_cntr 1)              ;find offending characters
                  )

                  (set_window wndw2)               ;move to window #2
                  (attach_buffer buf2)             ;atach buffer #2 to it
                  (move_abs line2 col2)            ;move back to offending
                                                   ;line
                  (move_rel 0 char_cntr)           ;reposition cursor after
                                                   ;offending character
                  (center_line)                    ;center line in window
                  (refresh)                        ;refresh

                  (set_window wndw1)               ;do same as above for
                                                   ;window #1
                  (attach_buffer buf1)
                  (move_abs line1 col1)
                  (move_rel 0 char_cntr)
                  (center_line)
                  (refresh)

                  (if (< char_cntr 6)              ;create fragment strings
                                                   ;for error message

                     (                             ;do this section if
                                                   ;first offending character
                                                   ;is within 5 characters
                                                   ;of beginning of line
                        (= string1 (substr string1 1 (+ char_cntr 5)))
                        (= string1 (+ string1 ".."))
                        (= string2 (substr string2 1 (+ char_cntr 5)))
                        (= string2 (+ string2 ".."))
                     )
                  ;else                            ;else do this ...
                     (
                        (= string1 (substr string1 (- char_cntr 5) 11))
                        (= string1 (+ ".." string1))
                        (= string1 (+ string1 ".."))
                        (= string2 (substr string2 (- char_cntr 5) 11))
                        (= string2 (+ ".." string2))
                        (= string2 (+ string2 ".."))
                     )
                  )
                  (= err_string (+ "'" string1))   ;build error string
                  (= err_string (+ err_string "' | '"))
                  (= err_string (+ err_string string2))
                  (= err_string (+ err_string "'"))

                  (beep)
                  (error "Mismatch: %s" err_string)   ;display error
                  (return -1)                         ;exit, leaving
                                                      ;hot key assigned
                                                      ;for subsequent
                                                      ;comparing
               )
            )
         )
      )
   )
)
